#include "main.h"
#include "sparse.h"
#include  "decoder.h"
#include  "decoder_q.h"
#include  "check.h"
#include  "encoder.h"
#include  "channel.h"
#include  "message.h"
#include  "modem.h"

#define DIGEST "CodeLength=2048, CodeRate=1/2, quantize=1, bit_w=4, v_max=dyn."

double  startsnr=-6.0;//0.7;
double	endsnr= 50.0;//0.9;
double	snrstep=0.2;


char codeName[40];

int QC_H[MB_FAC][NB_FAC];//check matrix in given in Quasi Cyclic term
int Un_BER,De_BER,Un_FER,De_FER;                  //vector stores erros of each iterave
int De_BER_P, Un_BER_P=0, De_FER_P=0, Un_FER_P;
int encode_err, encode_ir;
char DecodedData[EncodedLength];     //vector stores code decoded
mod2sparse *H;                       //pointer point to a sparse matrix with the link structure



/*function: fist read the generation check and informationlocation matrix from given files
            second generate link table of given LDPC matrix
            third  simulating the process of the encoding  transforming and deconding*/
void main()
{ 	
	Read_Matrix(QC_H);

	H=Make_QCLDPC(QC_H,NB_FAC,MB_FAC,Z_FAC);

    simulation();  
}

/*function: simulating the process of the encoding transforming and decoding
            calculating the BER after each iteration.
  parameter: infoBitLocation[] the position of information in a liner block code */
void simulation()
{	//extern char DecodedData[EncodedLength];
	double snr,Es_N0,N0, Eb_N0;
	double Un_ber,De_ber,Un_fer,De_fer,Total_fer,Total_ber;
	double Un_ber_p,De_ber_p,Un_fer_p,De_fer_p,Total_fer_p,Total_ber_p;
	char InfoData[InfoLength];	//={1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1};
	char EncodeData[EncodedLength];
	char EncodeCheck1[ParityCheckNum];
	int chk1=0, chk2=0;
	char TransmitData[REP_LEN];
	double ReceiveData[REP_LEN],llr_p[REP_LEN], llratio[EncodedLength],BitProb[EncodedLength];	//lratio[EncodedLength]
	char   ParityData[ParityCheckNum],filename[20];
	int    TotalNum,gogo;
	int decode_ir;
	double decode_ir_m;
	extern int encode_err, encode_ir;
	extern int Un_BER,De_BER,Un_FER,De_FER;
	extern int De_BER_P, Un_BER_P, De_FER_P, Un_FER_P;
	FILE *file,*file_dst, *fp_bit, *fp_in, *fp_out;
	time_t theTime;
	int i,j,llratio_q[EncodedLength],BitProb_q[EncodedLength];
	int csum;
	int err_p;
	int BE, FE, FE1, Tatalbit;
	char rep_data[REP_LEN];
	int len_syb;
	short llr_in[EncodedLength];
	char *pr_llr_in;
	char llr_out[EncodedLength];
	short *pr_llr_out;


	sprintf(filename,"result.txt");
	if( ( file = fopen( filename, "a" ) ) == NULL )
	{	
		printf( "can't open the file\n" );
		exit( 1 );
	}
	time(&theTime);
	fprintf(file, "\n\n\n//------- %s: z=%d  -- %s", codeName, Z_FAC, ctime(&theTime));

	if( ( file_dst = fopen( "distance.txt", "a" ) ) == NULL )
	{	
		printf( "can't open the file\n" );
		exit( 1 );
	}
	time(&theTime);
    fprintf(file_dst, "\n\n//------- %s", ctime(&theTime));
	
	if ((fp_in = fopen("llr_in1_2d3_90.txt", "r")) == NULL)
	{
		printf("can't open the file\n");
		exit(1);
	}

	if ((fp_out = fopen("llr_out.txt", "w")) == NULL)
	{
		printf("can't open the file\n");
		exit(1);
	}

	if ((fp_bit = fopen("bit_out.txt", "w")) == NULL)
	{
		printf("can't open the file\n");
		exit(1);
	}
	
	for(snr = startsnr;snr <= endsnr;snr += snrstep)
	{	
		TotalNum = 0;
		gogo=1;
		srand( (unsigned) time(NULL) );
		Eb_N0 = pow( 10, snr/10.);		
    	//N0 = realsnr;//signal to noise
		N0 = 1 / (Eb_N0);	// *CodeRate);			//N0=1/Es_N0, Es_N0=Eb_N0*CodeRate, sigma=sqrt(n0/2)
		De_BER=0; 
		Un_BER=0;
		De_FER=0;
		Un_FER=0;
		decode_ir=0;
		De_BER_P=0; 
		Un_BER_P=0;
		De_FER_P=0;
		Un_FER_P=0;
		FE1 = 0;
		while(gogo==1)
		{
			input(InfoData);

			encode(QC_H, InfoData, EncodeData, MB_FAC, KB_FAC, Z_FAC);
			chk1 = check(H,EncodeData,EncodeCheck1);
			if(chk1 != 0)
			{
				printf("error! chk=%d\n", chk2);
				break;
			}

			for (i=0; i<EncodedLength; i++)
			{
				for (j=0; j<REP_NUM; j++)
				{
					rep_data[i*REP_NUM+j] = EncodeData[i];
				}
			}


			bpsk(rep_data, TransmitData);
			awgn(TransmitData, ReceiveData, N0);
			de_bpsk(ReceiveData, llr_p, N0);

			for (i=0; i<EncodedLength; i++)
			{
				llratio[i] = 0.0;
				for (j=0; j<REP_NUM; j++)
				{
					llratio[i] += llr_p[i*REP_NUM+j];
				}
			}

			for (i=0; i<EncodedLength; i++)
				llratio_q[i] = quan(llratio[i], QSTEP);
			for (i = 0; i<zero_len; i++)
				llratio_q[i] = 63;

			//for (i = 0; i < EncodedLength; i++)
				//fscanf(fp_in, "%d", llratio_q+i);
			//fclose(fp_in);

			//for (i = 0; i < EncodedLength; i++)
			//	fprintf(fp_out, "%d\n", llratio_q[i]);
			//fclose(fp_out);

//			decode_ir += prprp_decode( H,llratio, DecodedData, ParityData,BitProb,InfoData,&csum);
			decode_ir += prprp_decode_q( H,llratio_q, DecodedData, ParityData,BitProb_q,InfoData,&csum);

			//for (i = 0; i < EncodedLength; i++)
			//	fprintf(fp_bit, "%d\n", DecodedData[i]);
			//fclose(fp_bit);

  		    TotalNum++;

			err_p = 0;
			for (i=0; i<EncodedLength; i++)
			{
				if(EncodeData[i]!=DecodedData[i])
					err_p++;
			}

			if (csum!=0)
				FE1++;

			Un_ber_p = (double)Un_BER_P / ((double)(TotalNum)*InfoLength_real);
			Un_fer_p = (double)Un_FER_P / (double)TotalNum;
			De_ber_p = (double)De_BER_P / ((double)(TotalNum)*InfoLength_real);
			De_fer_p = (double)De_FER_P / (double)TotalNum;
			Total_fer_p = Un_fer_p + De_fer_p;
			Total_ber_p = Un_ber_p + De_ber_p;

			Un_ber = (double)Un_BER / ((double)(TotalNum)*InfoLength_real);
			Un_fer = (double)Un_FER / (double)TotalNum;
			De_ber = (double)De_BER / ((double)(TotalNum)*InfoLength_real);
			De_fer = (double)De_FER / (double)TotalNum;
			 decode_ir_m = (double)decode_ir/(double)TotalNum;
			 BE = Un_BER + De_BER;
			 FE = Un_FER + De_FER;
			 Total_fer=Un_fer+De_fer;
			 Total_ber=Un_ber+De_ber;
			 Tatalbit = TotalNum*InfoLength_real;
			if(TotalNum%100==0)
			{
				printf("\nsnr=%1.1f TotalNum=%4d Tatalbit=%d BE=%d FE=%d FE1=%d Total_ber=%1.8f Total_fer=%1.8f", snr,TotalNum,Tatalbit, BE, FE, FE1, Total_ber,Total_fer);
			}

			if((TotalNum>=400) && (De_FER+Un_FER)>= Totalerror )
				break;

		}
		
        fprintf(file,"\nsnr=%1.8f TotalNum=%4d Total_ber=%1.8f Total_fer=%1.8f", snr,TotalNum,Total_ber,Total_fer);
		fflush(file);
		fflush(file_dst);
}
	fclose(file);
	fclose(file_dst);
}

void Read_Matrix(int T[][NB_FAC])
{
    int i,j;

	sprintf(codeName, "hmx_1d4_12X16_m128_48.txt");
	//sprintf(codeName, "hmx_1d3_16X24_m128_24.txt");
	
	
	
	
	

    FILE *file;
    if((file=fopen(codeName, "r"))==NULL)
    {
        printf("can't open the file\n");
        exit(1);
    }

    printf("\n");
    if( MB_FAC )
    {
        for( i = 0; i < MB_FAC; i++ )
        {
            for( j = 0; j < NB_FAC; j++ ) 
            {
                fscanf( file, "%d", &T[i][j]);
                if(T[i][j]>=0)
                    T[i][j] = (int)((double)(T[i][j]) * ((double)(Z_FAC)/(double)(Z_MAX)));
                printf("%4d",T[i][j]);
            }
            printf("\n");
        }
    }
    else
        T = NULL;
    fclose(file);
}
